package net.documentshare.utils.doc;

import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfReader;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.io.*;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * 
 * PDF 转换器
 */
public class PDFConverter {
	private static final Log LOGGER = LogFactory.getLog(PDFConverter.class);
	private static String COMMAND = "";
	private static Integer SINGLE_PAGE_MODE_MAX_THREAD = 5;
	private static Integer convertPages = 30;

	public static void setCommand(String command) {
		PDFConverter.COMMAND = command;
		LOGGER.debug("设置命令配置为 :" + command);
	}

	public static void setConvertPages(int convertPages) {
		PDFConverter.convertPages = convertPages;
		LOGGER.debug("设置命令配置为 :" + convertPages);
	}

	public static String getCommand() {
		return COMMAND;
	}

	public static void setSinglePageModeMaxThread(Integer value) {
		PDFConverter.SINGLE_PAGE_MODE_MAX_THREAD = value;
		LOGGER.debug("设置单页面转换模式最大线程配置为 :" + value);
	}

	public static Integer getSinglePageModeMaxThread() {
		return SINGLE_PAGE_MODE_MAX_THREAD;
	}

	public static void setOnePageModeMaxThreadConfig(Integer value) throws Exception {
		setSinglePageModeMaxThread(value);
	}

	public static void setCommandConfig(String command) throws Exception {
		setCommand(command);
	}

	public int execConvertCommand(String command, final List<String> outResources) throws InterruptedException, IOException {
		LOGGER.debug(command);
		final Process convertProcess = Runtime.getRuntime().exec(command);
		final InputStream inputStream = convertProcess.getInputStream();
		final InputStream errorStream = convertProcess.getErrorStream();

		new Thread() {
			public void run() {
				BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
				try {
					String line = null;

					while ((line = br.readLine()) != null) {
						if (line != null) {
							if (outResources != null) {
								outResources.add(line);
							}
							LOGGER.debug(line);
						}
					}
				} catch (IOException e) {
					LOGGER.error(e);
				}
			}
		}.start();
		new Thread() {
			public void run() {
				BufferedReader br = new BufferedReader(new InputStreamReader(errorStream));
				try {

					String line = null;
					while ((line = br.readLine()) != null) {
						if (line != null) {
							LOGGER.debug(line);
							if (outResources != null) {
								outResources.add(line);
							}
						}
					}
				} catch (IOException e) {
					LOGGER.error(e);
				}
			}
		}.start();
		convertProcess.waitFor();
		return convertProcess.exitValue();
	}

	private PDFConverterDeploy deploy(ConvertParam param) throws Exception, DocumentException {
		if (!param.pdfFile.isFile() || !param.pdfFile.exists()) {
			throw new Exception("Not a Valid PDF File!");
		}
		String pdfPath = param.pdfFile.getPath();
		String pdfFullName = param.pdfFile.getName();
		int i = pdfFullName.toLowerCase().lastIndexOf(".pdf");
		if (i == -1) {
			throw new Exception("Not a Valid PDF File!");
		}
		String pdfName = pdfFullName.substring(0, i);
		LOGGER.debug("---加载文档---");

		// File outputDirectory = new
		// File(FileUtils.appendFileSeparator(outPath) + pdfName);
		//
		//
		// //if is a file , backup the file
		// if (outputDirectory.isFile()) {
		// outputDirectory.renameTo(new File(outputDirectory.getPath() +
		// ".backup"));
		// }
		//
		// if (!outputDirectory.exists()) {
		// outputDirectory.mkdirs();
		// }
		//
		// outPath = FileUtils.appendFileSeparator(outputDirectory.getPath());

		PdfReader reader = new PdfReader(pdfPath);
		int pageCount = reader.getNumberOfPages();

		// if pdf is a encrypted file unencrypted
		if (reader.isEncrypted()) {
			LOGGER.debug("encrypted pdf! 准备另存");
			pdfPath = PDFSecurer.decrypt(reader,
					FileUtils.appendFileSeparator(param.outPath) + FileUtils.getFilePrefix(param.pdfFile) + "_decrypted.pdf").getPath();
			LOGGER.debug("PDF解密完成");
		} else {
			LOGGER.debug("---文档未加密---");
		}
		reader.close();
		// 写页数到文件
		// if (pageCount != 0) {
		// OutputStream out = null;
		// try {
		// File info = new File(FileUtils.appendFileSeparator(outPath) +
		// "info");
		// info.createNewFile();
		// out = new FileOutputStream(info);
		// out.write((pageCount + "").getBytes("UTF-8"));
		// } finally {
		// if (out != null) {
		// out.flush();
		// out.close();
		// }
		// }
		// }
		return new PDFConverterDeploy(new File(param.outPath), pageCount, COMMAND.replace("${in}", pdfPath).replace("${out}",
				param.outPath + File.separator + (param.splitPage ? "page%.swf" : "page.swf"))
				+
				// 是否将图片转换成点阵形式
				(param.poly2bitmap ? " -s poly2bitmap" : ""));
	}

	public PDFConvertError checkError(List<String> outResources) {
		boolean errorMsg = false;
		int position = -1;
		String item;
		PDFConvertError error = new PDFConvertError();
		for (int i = outResources.size() - 1; i >= 0; i--) {
			item = outResources.get(i);
			if (errorMsg == false) {
				if (item.lastIndexOf(PDFConvertErrorType.COMPLEX.getErrorMessage()) > -1) {
					errorMsg = true;
					error.setType(PDFConvertErrorType.COMPLEX);
				} else if (item.lastIndexOf(PDFConvertErrorType.INVALID_CHARID.getErrorMessage()) > -1) {
					errorMsg = true;
					error.setType(PDFConvertErrorType.INVALID_CHARID);
				}
			} else if (position == -1) {
				String reg = "NOTICE  processing PDF page ";
				position = item.lastIndexOf(reg);
				if (position != -1) {
					item = item.replace(reg, "");
					error.setPosition(Integer.parseInt(item.split(" ")[0]));
				}
			}
		}
		return error;
	}

	private void errorHandler(List<String> outResources, final ConvertParam param) throws Exception {
		// 如果第一次没有将图片转换成点阵图报错，则进行第二次转换，并将图片转换成点阵
		final PDFConvertError error = checkError(outResources);
		if (error.getType() == PDFConvertErrorType.COMPLEX && param.poly2bitmap != true) {
			LOGGER.debug("---第一次转换失败，进行第二次转换---");
			if (param.splitPage) {
				new Thread() {
					public void run() {
						try {
							convert(param, error.getPosition(), error.getPosition(), true, true);
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				}.start();
				convertAsOnePageMode(param, error.getPosition() + 1);
			} else {
				convert(param, true);
			}
		} else {
			throw new Exception("Conversion failed:" + error.getType() + ";\n" + StringUtils.join(outResources, "\n"));
		}
	}

	public void run(String command, ConvertParam param) throws Exception {
		LOGGER.debug("---转换开始---");
		List<String> outResources = new ArrayList<String>();
		if (execConvertCommand(command, outResources) != 0) {
			errorHandler(outResources, param);
		}
		LOGGER.debug("---转换结束---");
	}

	// public File convertAsOnePageMode(File pdfFile, String outPath) throws
	// Exception {
	// return convertAsOnePageMode(pdfFile, outPath, 1, null, false);
	// }
	//
	public File convertAsOnePageMode(ConvertParam param, int startPage) throws Exception {
		return convertAsOnePageMode(param, startPage, null, false);
	}

	// public File convertAsOnePageMode(File pdfFile, String outPath, boolean
	// poly2bitmap) throws Exception {
	// return convertAsOnePageMode(pdfFile, outPath, 1, null, poly2bitmap);
	// }

	public File convertAsOnePageMode(ConvertParam param, final int startPage, final Integer endPage, final boolean poly2bitmap) throws Exception {
		final List<Thread> pool = new LinkedList<Thread>();
		int covertCount = 0;
		ConvertParam newParam = (ConvertParam) BeanUtils.cloneBean(param);
		newParam.splitPage = true;
		newParam.poly2bitmap = poly2bitmap;
		PDFConverterDeploy deploy = deploy(newParam);
		String command = deploy.getCommand();
		int page = getSinglePageModeMaxThreadCount(deploy);
		int pageCount = deploy.getPageCount();
		for (int i = startPage; i <= (endPage == null || endPage > pageCount ? pageCount : endPage); i++) {
			final int nowPage = i;
			final String commandExec = command += " -p " + nowPage;
			Thread t = new Thread() {
				public void run() {
					List<String> outResources = new ArrayList<String>();
					try {
						if (execConvertCommand(commandExec, outResources) != 0) {
							PDFConvertError error = checkError(outResources);
							if (error.getType() == PDFConvertErrorType.COMPLEX && poly2bitmap != true) {
								LOGGER.debug("---第一次转换失败，进行第二次转换---");
								execConvertCommand(commandExec + " -s poly2bitmap", outResources);
							} else if (error.getType() != PDFConvertErrorType.NONE) {
								throw new Exception("Conversion failed:" + error.getType() + ";\n" + StringUtils.join(outResources, "\n"));
							}
						}
					} catch (Exception e) {
						LOGGER.error(e);
						e.printStackTrace();
					}

				}
			};
			pool.add(t);
			t.start();
			covertCount++;
			if (covertCount == page) {
				for (Thread thread : pool) {
					thread.join();
				}
				pool.removeAll(pool);
				covertCount = 0;
			}
		}
		return deploy.getOutputDirectory();
	}

	public File convert(final ConvertParam param, int startPage, Integer endPage, boolean splitPage, boolean poly2bitmap) throws Exception {
		ConvertParam newParam = (ConvertParam) BeanUtils.cloneBean(param);
		newParam.splitPage = splitPage;
		newParam.poly2bitmap = poly2bitmap;
		PDFConverterDeploy deploy = deploy(newParam);
		String command = deploy.getCommand();
		int pageCount = deploy.getPageCount();
		command += " -p " + startPage
				+ (endPage != null && startPage == endPage ? "" : "-" + (endPage == null || endPage > pageCount ? pageCount : endPage));

		run(command, newParam);
		return deploy.getOutputDirectory();
	}

	// public File convert(File pdfFile, String outPath) throws Exception {
	// return convert(pdfFile, outPath, true, false);
	// }
	//
	public File convert(final ConvertParam param, boolean poly2bitmap) throws Exception {
		ConvertParam newParam = (ConvertParam) BeanUtils.cloneBean(param);
		newParam.splitPage = true;
		newParam.poly2bitmap = poly2bitmap;
		return convert(newParam);
	}

	/**
	 * pdf转换为swf
	 * 
	 * @param pdfFile
	 * @param outPath
	 * @param splitPage
	 * @param poly2bitmap
	 * @return 返回转换后输出文件目录
	 * @throws Exception
	 */
	public File convert(ConvertParam param) throws Exception {
		LOGGER.debug("---准备转换文档---");
		PDFConverterDeploy deploy = deploy(param);
		String command = deploy.getCommand();
		if (net.simpleframework.util.StringUtils.hasText(param.convertPages)) {
			command = deploy.getCommand() + " -p 1-" + param.convertPages;
		} 
		run(command, param);
		System.out.println("文档转化成功"+command);
		return deploy.getOutputDirectory();
	}

	public int getSinglePageModeMaxThreadCount(PDFConverterDeploy deploy) {
		int pageCount = deploy.getPageCount();
		if (SINGLE_PAGE_MODE_MAX_THREAD < 1) {
			return pageCount;
		} else {
			return SINGLE_PAGE_MODE_MAX_THREAD > pageCount ? pageCount : SINGLE_PAGE_MODE_MAX_THREAD;
		}
	}

}
